﻿#include "Program.h"
#include "Settings.h"
#include "../Shared/Packet.h"

using namespace Launcher;

namespace Client
{

CMain *Program::Form;
AMain *Program::PForm;
bool Program::Restart = false;

    void Program::Main(std::vector<std::string> &args)
    {
        if (args.size() > 0)
        {
            for (auto arg : args)
            {
                if (arg.ToLower() == "-tc")
                {
                    Settings::setUseTestConfig(true);
                }
            }
        }

        #if defined(DEBUG)
            Settings::setUseTestConfig(true);
        #endif

        try
        {
            if (UpdatePatcher())
            {
                return;
            }

            if (RuntimePolicyHelper::getLegacyV2RuntimeEnabledSuccessfully() == true)
            {
            }

            Packet::IsServer = false;
            Settings::Load();

            Application::EnableVisualStyles();
            Application::SetCompatibleTextRenderingDefault(false);

            if (Settings::P_Patcher)
            {
                Launcher::AMain tempVar();
                Application::Run(PForm = &tempVar);
            }
            else
            {
                CMain tempVar2();
                Application::Run(Form = &tempVar2);
            }

            Settings::Save();
            CMain::InputKeys->Save();

            if (Restart)
            {
                Application::Restart();
            }
        }
        catch (const std::runtime_error &ex)
        {
            CMain::SaveError(ex.what());
        }
    }

    bool Program::UpdatePatcher()
    {
        try
        {
            const std::string fromName = R"(.\AutoPatcher.gz)", toName = R"(.\AutoPatcher.exe)";
            if (!FileSystem::fileExists(fromName))
            {
                return false;
            }

            std::vector<Process*> processes = Process::GetProcessesByName("AutoPatcher");

            if (processes.size() > 0)
            {
                std::string patcherPath = Application::StartupPath + R"(\AutoPatcher.exe)";

                for (int i = 0; i < processes.size(); i++)
                {
                    if (processes[i]->MainModule->FileName == patcherPath)
                    {
                        processes[i]->Kill();
                    }
                }

                Stopwatch *stopwatch = Stopwatch::StartNew();
                bool wait = true;
                processes = Process::GetProcessesByName("AutoPatcher");

                while (wait)
                {
                    wait = false;
                    for (int i = 0; i < processes.size(); i++)
                    {
                        if (processes[i]->MainModule->FileName == patcherPath)
                        {
                            wait = true;
                        }
                    }

                    if (stopwatch->ElapsedMilliseconds <= 3000)
                    {
                        continue;
                    }
                    MessageBox::Show("Failed to close AutoPatcher during update.");
                    return true;
                }
            }

            if (FileSystem::fileExists(toName))
            {
                File::Delete(toName);
            }
            FileSystem::renamePath(fromName, toName);
            Process::Start(toName, "Auto");

            return true;
        }
        catch (const std::runtime_error &ex)
        {
            CMain::SaveError(ex.what());

            throw;
        }
    }

bool Program::RuntimePolicyHelper::LegacyV2RuntimeEnabledSuccessfully = false;

    bool Program::RuntimePolicyHelper::getLegacyV2RuntimeEnabledSuccessfully()
    {
        return LegacyV2RuntimeEnabledSuccessfully;
    }

    void Program::RuntimePolicyHelper::setLegacyV2RuntimeEnabledSuccessfully(bool value)
    {
        LegacyV2RuntimeEnabledSuccessfully = value;
    }

    Program::RuntimePolicyHelper::StaticConstructor::StaticConstructor()
    {
//C# TO C++ CONVERTER TODO TASK: There is no C++ equivalent to the C# 'typeof' operator:
        ICLRRuntimeInfo *clrRuntimeInfo = std::any_cast<ICLRRuntimeInfo*>(RuntimeEnvironment::GetRuntimeInterfaceAsObject(Guid::Empty, typeof(ICLRRuntimeInfo)->GUID));
        try
        {
            clrRuntimeInfo->BindAsLegacyV2Runtime();
            setLegacyV2RuntimeEnabledSuccessfully(true);
        }
        catch (const COMException &e1)
        {
            // This occurs with an HRESULT meaning 
            // "A different runtime was already bound to the legacy CLR version 2 activation policy."
            setLegacyV2RuntimeEnabledSuccessfully(false);
        }
    }

RuntimePolicyHelper::StaticConstructor Program::RuntimePolicyHelper::staticConstructor;
}
